﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Configuration;
using System.Web.Script.Serialization;
using System.Web.Services;
using System.Web.UI;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.SharePoint.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;

namespace SharePointApp3Web.Pages
{
    public partial class Default : Page
    {
        private static string currentSystemUserGuid = string.Empty;
        private static readonly OrganizationServiceProxy orgService = GetOrganizationService();
        private readonly List<Task> lstTask = new List<Task>();
        private readonly List<ListDetail> lstTaskTypes = new List<ListDetail>();
        private string currentUserEmailId = string.Empty;
        private int currentUserIdForTask;

        /// <summary>
        ///     Handles the Load event of the Page control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            // The following code gets the client context and Title property by using TokenHelper.
            // To access other properties, you may need to request permissions on the host web.


            string contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
            string hostWeb = Page.Request["SPHostUrl"];
          

            using (
                ClientContext clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken,
                    Request.Url.Authority))
            {
                //Load the properties for the Web' Current User
                Web web = clientContext.Web;

                clientContext.Load(web);
                clientContext.Load(web.CurrentUser);
                clientContext.ExecuteQuery();


                currentUserEmailId = clientContext.Web.CurrentUser.LoginName.Substring(clientContext.Web.CurrentUser.LoginName.LastIndexOf("|") + 1);

          
                currentUserIdForTask = clientContext.Web.CurrentUser.Id;


     
                // Get all the list of type Tasks
                ListCollection listCollection = clientContext.Web.Lists;

                // 
                IQueryable<List> queryExpressionForTaskList = from list
                    in listCollection.Include(
                        list => list.Title,
                        list => list.ListItemEntityTypeFullName,
                        list => list.DefaultDisplayFormUrl
                        )
                    where list.BaseTemplate == 171
                          && list.Hidden != true
                    select list;

                IEnumerable<List> taskListCollection = clientContext.LoadQuery(queryExpressionForTaskList);
                clientContext.ExecuteQuery();


              

                var listItemQuery = new CamlQuery();

                listItemQuery.ViewXml =
                    "<View><Query><Where><And><Eq><FieldRef Name='AssignedTo' LookupId='TRUE'/><Value Type='Lookup'>" +
                    currentUserIdForTask +
                    "</Value></Eq><Neq><FieldRef Name='Status' /><Value Type='Text'>Completed</Value></Neq></And></Where></Query></View>";


                ListDetail lstDetail;
                // add a CRM Task Type default
                lstDetail = new ListDetail();
                lstDetail.listName = "CRM";
                lstDetail.listEntityTypeFullName = "CRM";
                lstTaskTypes.Add(lstDetail);

                foreach (List taskList in taskListCollection)
                {
                    lstDetail = new ListDetail();
                    lstDetail.listName = taskList.Title;
                    lstDetail.listEntityTypeFullName = taskList.ListItemEntityTypeFullName;
                    lstTaskTypes.Add(lstDetail);

                    // One or more field types are not installed properly. Go to the list settings page to delete these fields.
                    ListItemCollection listItemCollection = taskList.GetItems(listItemQuery);

                    // load the itemcollection in clientcontext
                    clientContext.Load(listItemCollection);
                    clientContext.ExecuteQuery();


                    Task task;
                    foreach (ListItem listItem in listItemCollection)
                    {
                        task = new Task();
                        task.id = listItem.FieldValues["ID"].ToString();
                        task.title = listItem.FieldValues["Title"].ToString();
                        task.start = ((DateTime) listItem.FieldValues["StartDate"]).ToLocalTime().ToString();
                        task.end = ((DateTime) listItem.FieldValues["DueDate"]).ToLocalTime().ToString();
                        task.priority = listItem.FieldValues["Priority"].ToString();
                        if (listItem.FieldValues["Body"] != null)
                        {
                            task.description = listItem.FieldValues["Body"].ToString();
                        }
                        else
                        {
                            task.description = "NA";
                        }
                        task.color = "slategray";
                        task.allDay = false;
                        task.taskListName = taskList.Title;
                        task.listEntityTypeFullName = taskList.ListItemEntityTypeFullName;
                        task.type = "SP";
                        task.taskUrl = hostWeb + "/Lists/" + taskList.Title + "/DispForm.aspx?ID=" + task.id;
                        lstTask.Add(task);
                    }
                }

                currentUserEmailId = clientContext.Web.CurrentUser.LoginName.Substring(clientContext.Web.CurrentUser.LoginName.LastIndexOf("|") + 1);
                // currentUserEmailId = "ShraddhaDhingra@hughgrant.onmicrosoft.com";

                //// Get CRM Tasks
                //OrganizationServiceProxy orgService = GetOrganizationService();
                //// based on username get the callerid for the CRM User
                var queryExp = new QueryExpression("systemuser");
                queryExp.ColumnSet.AddColumn("systemuserid");
                queryExp.ColumnSet.AddColumn("fullname");
                queryExp.Criteria.AddCondition(new ConditionExpression("internalemailaddress", ConditionOperator.Equal,
                    currentUserEmailId));

                EntityCollection entityColl = orgService.RetrieveMultiple(queryExp);
                if (entityColl.Entities.Count > 0)
                {
                    currentSystemUserGuid = entityColl[0].Attributes["systemuserid"].ToString();
                    string fullName = entityColl[0].Attributes["fullname"].ToString();

                   Label1.Text = "Welcome: <b>" + fullName + "</b>";

                  //  Label1.Text = "Welcome: <b> Fav Sis </b>";

                    // do impersonation here by setting the caller id
                    orgService.CallerId = new Guid(currentSystemUserGuid);
                    var queryExpression = new QueryExpression("task");
                    var conditionExpression1 = new ConditionExpression("statecode", ConditionOperator.Equal,
                        0);
                    var conditionExpression2 = new ConditionExpression("ownerid", ConditionOperator.Equal,
                        currentSystemUserGuid);
                    queryExpression.ColumnSet =
                        new ColumnSet(new[]
                        {"activityid", "subject", "scheduledstart", "scheduledend", "description", "prioritycode"});
                    queryExpression.Criteria.AddCondition(conditionExpression1);
                    queryExpression.Criteria.AddCondition(conditionExpression2);
                    queryExpression.Criteria.FilterOperator = LogicalOperator.And;
                    EntityCollection taskCollection = orgService.RetrieveMultiple(queryExpression);

                    Task crmTask;
                    foreach (Entity entity in taskCollection.Entities)
                    {
                        crmTask = new Task();
                        crmTask.id = ((Guid) entity.Attributes["activityid"]).ToString();
                        crmTask.title = entity.Attributes["subject"].ToString();
                        crmTask.start = ((DateTime) entity.Attributes["scheduledstart"]).ToLocalTime().ToString();
                        crmTask.end = ((DateTime) entity.Attributes["scheduledend"]).ToLocalTime().ToString();
                        crmTask.color = "#3A79B8";
                        crmTask.allDay = false;
                        if (entity.Attributes.Contains("description"))
                        {
                            crmTask.description = entity.Attributes["description"].ToString();
                        }
                        else
                        {
                            crmTask.description = "NA";
                        }

                        var priorityCodeValue = (OptionSetValue) (entity.Attributes["prioritycode"]);
                        if (priorityCodeValue.Value == 0)
                        {
                            crmTask.priority = "Low";
                        }
                        else if (priorityCodeValue.Value == 1)
                        {
                            crmTask.priority = "Normal";
                        }
                        else if (priorityCodeValue.Value == 2)
                        {
                            crmTask.priority = "High";
                        }

                        crmTask.taskListName = "CRM List";
                        crmTask.type = "CRM";

                        crmTask.taskUrl = WebConfigurationManager.AppSettings.Get("CrmTaskUrl") + "&id={" + crmTask.id +
                                          "}";

                        lstTask.Add(crmTask);
                    }


                    var objectSerializer = new JavaScriptSerializer();
                    string objectJson = objectSerializer.Serialize(lstTask);
                    string taskTypeJson = objectSerializer.Serialize(lstTaskTypes);

                    hiddenObject.Value = objectJson;
                    hiddenTaskType.Value = taskTypeJson;
                    hiddenSharePointUserId.Value = currentUserIdForTask.ToString();
                    hiddenCrmTaskUrl.Value = WebConfigurationManager.AppSettings.Get("CrmTaskUrl") + "&id=";
                }
            }
        }


        /// <summary>
        ///     Gets the organization service.
        /// </summary>
        /// <returns></returns>
        public static OrganizationServiceProxy GetOrganizationService()
        {
            IServiceManagement<IOrganizationService> orgServiceManagement =
                ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
                    new Uri(WebConfigurationManager.AppSettings.Get("CrmOrgServiceUrl")));
            var authCredentials = new AuthenticationCredentials();
            authCredentials.ClientCredentials.UserName.UserName = WebConfigurationManager.AppSettings.Get("UserName");
            authCredentials.ClientCredentials.UserName.Password = WebConfigurationManager.AppSettings.Get("Password");
            AuthenticationCredentials tokenCredentials = orgServiceManagement.Authenticate(authCredentials);
            return new OrganizationServiceProxy(orgServiceManagement, tokenCredentials.SecurityTokenResponse);
        }


        /// <summary>
        ///     Updates the task in CRM.
        /// </summary>
        /// <param name="taskGuid">The task unique identifier.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="dueDate">The due date.</param>
        [WebMethod]
        public static void UpdateTaskInCRM(string taskGuid, string startDate, string dueDate)
        {
            //  OrganizationServiceProxy orgService = GetOrganizationService();

            var taskEntity = new Entity();
            taskEntity.LogicalName = "task";
            taskEntity.Id = new Guid(taskGuid);
            taskEntity.Attributes["scheduledstart"] = Convert.ToDateTime(startDate);
            if (dueDate != string.Empty)
            {
                taskEntity.Attributes["scheduledend"] = Convert.ToDateTime(dueDate);
            }

            // implement impersonation
            orgService.CallerId = new Guid(currentSystemUserGuid);
            orgService.Update(taskEntity);
        }


        /// <summary>
        ///     Sets the state task in CRM.
        /// </summary>
        /// <param name="taskGuid">The task unique identifier.</param>
        [WebMethod]
        public static void SetStateTaskInCRM(string taskGuid)
        {
            //   OrganizationServiceProxy orgService = GetOrganizationService();

            var req = new SetStateRequest();
            req.EntityMoniker = new EntityReference("task", new Guid(taskGuid));
            req.State = new OptionSetValue(1);
            req.Status = new OptionSetValue((5));

            // implement impersonation
            orgService.CallerId = new Guid(currentSystemUserGuid);
            orgService.Execute(req);
        }

        /// <summary>
        ///     Creates the task in CRM.
        /// </summary>
        /// <param name="taskTitle">The task title.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="dueDate">The due date.</param>
        /// <param name="description">The description.</param>
        /// <param name="priority">The priority.</param>
        /// <returns></returns>
        [WebMethod]
        public static string CreateTaskInCRM(string taskTitle, string startDate, string dueDate, string description,
            string priority)
        {
            //       OrganizationServiceProxy orgService = GetOrganizationService();

            var taskEntity = new Entity();
            taskEntity.LogicalName = "task";

            taskEntity.Attributes["subject"] = taskTitle;
            taskEntity.Attributes["scheduledstart"] = Convert.ToDateTime(startDate);
            if (dueDate != string.Empty)
            {
                taskEntity.Attributes["scheduledend"] = Convert.ToDateTime(dueDate);
            }
            taskEntity.Attributes["description"] = description;
            taskEntity.Attributes["ownerid"] = new EntityReference("systemuser", new Guid(currentSystemUserGuid));

            int prioriyCode = default(int);
            if (priority == "Low")
            {
                prioriyCode = 0;
            }
            else if (priority == "Normal")
            {
                prioriyCode = 1;
            }
            else if (priority == "High")
            {
                prioriyCode = 2;
            }

            taskEntity.Attributes["prioritycode"] = new OptionSetValue(prioriyCode);
            // implement impersonation
            orgService.CallerId = new Guid(currentSystemUserGuid);
            return orgService.Create(taskEntity).ToString();
        }
    }


    /// <summary>
    /// </summary>
    public class Task
    {
        public string id { get; set; }
        public string title { get; set; }
        public string start { get; set; }
        public string end { get; set; }
        public string color { get; set; }
        public bool allDay { get; set; }
        public string description { get; set; }
        public string priority { get; set; }
        // task name for identifying task list name in sharepoint
        public string taskListName { get; set; }
        public string type { get; set; }
        public string listEntityTypeFullName { get; set; }
        public string taskUrl { get; set; }
    }

    /// <summary>
    /// </summary>
    public class ListDetail
    {
        public string listName { get; set; }
        public string listEntityTypeFullName { get; set; }
    }
}